package org.ztest.invoke;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Date;

/**
 * Hello world!
 *
 */
public class MethodHandleTest
{
	private static int TEST_LOOP = 100000;
	
	public static void test() throws Throwable
	{
		MethodHandle handle = MethodHandles.lookup().findStatic(MethodHandleTest.class, "getIntervalBetweenTwoDay", MethodType.methodType(int.class, Date.class, Date.class));
		
		Method method = MethodHandleTest.class.getMethod("getIntervalBetweenTwoDay", Date.class, Date.class);
		
		Date d1 = new Date(10000000);
		Date d2 = new Date();
		
		System.out.println("MethodHandle.invoke    MethodHandle.invokeExact    getIntervalBetweenTwoDay    Method.invoke");
		
		for (int j = 0; j < 100; j++)
		{
			long start = System.currentTimeMillis();
			for (int i = 0; i < TEST_LOOP; i++)
			handle.invoke(d1, d2);
			System.out.print(System.currentTimeMillis() - start);
			System.out.print("	");
			
			start = System.currentTimeMillis();
			for (int i = 0; i < TEST_LOOP; i++)
			{
				@SuppressWarnings("unused")
				int obj = (int) handle.invokeExact(d1, d2);
			}
			System.out.print(System.currentTimeMillis() - start);
			System.out.print("	");
			
			start = System.currentTimeMillis();
			for (int i = 0; i < TEST_LOOP; i++)
			getIntervalBetweenTwoDay(d1, d2);
			System.out.print(System.currentTimeMillis() - start);
			System.out.print("	");
			
			start = System.currentTimeMillis();
			for (int i = 0; i < TEST_LOOP; i++)
			method.invoke(MethodHandleTest.class, d1, d2);
			System.out.println(System.currentTimeMillis() - start);
		}
	}
	
	private static final int MILLIS_PER_DAY = 24 * 60 * 60 * 1000; // 1天的毫秒数
	
	/**
	 * 计算2个日期之间隔了多少天
	 * <p>
	 * 将2个日期均推至各自的0点0分0秒0毫秒，然后得出2个日期的毫秒差，经过换算得到的值即2者天数之差
	 * <p>
	 * 不能直接使用{@link Calendar#get()}获取的日期直接做减法，要考虑跨年跨月等情况
	 * 
	 * @param dateOld 较早的日期
	 * @param dateNew 较晚的日期
	 * @return 参数{@code dateOld}和参数{@code dateNew}相隔的天数
	 */
	public static int getIntervalBetweenTwoDay(Date dateOld, Date dateNew)
	{
		Calendar calOld = Calendar.getInstance();
		calOld.setTime(dateOld);
		eraseTime(calOld);

		Calendar calNew = Calendar.getInstance();
		calNew.setTime(dateNew);
		eraseTime(calNew);

		long diffInMillis = calNew.getTimeInMillis() - calOld.getTimeInMillis();
		return (int) (diffInMillis / MILLIS_PER_DAY);
	}
	
	/**
	 * 擦除时分秒等信息
	 * @param cal
	 */
	private static void eraseTime(Calendar cal)
	{
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
	}
}
